<template>
  <div class="hello">
    <div id="map" class="map" tabindex="0"></div>
    <TyphoonInfo ref="typhoonInfo" :typhoonData="this.typhoonData" />
  </div>
</template>

<script>
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import {getTyphoonData} from "@/data/api";
import {Vector as VectorLayer} from 'ol/layer';
import {
  WMTS as WMTS,
  Vector as VectorSource,
} from "ol/source";
import Feature from 'ol/Feature';
import {LineString, MultiLineString, Point, Polygon} from 'ol/geom';
import {fromLonLat,get as getProjection } from "ol/proj";
import {Fill,Circle,Style} from "ol/style";
import featureObj from "../common/js/feature";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import { getTopLeft, getWidth } from "ol/extent";
import TyphoonInfo from "../components/typhoonInfo.vue";
import {Overlay} from "ol";


export default {
  name: 'HelloWorld',
  data() {
    return {
      map: null,
      lastShowSolar: null,
      lastZoomPoint: null,
      typhoonData: {},
      tfOverlay: null
    }
  },
  components: {
    TyphoonInfo,
  },
  methods:{
    //画出台风路径
    drawTyphoonPath: async function () {
      //检查是否拿到数据
      const {data} = await getTyphoonData();
      //新建一个layers然后装载数据源，数据源属性渲染，然后添加图层依据不同颜色渲染，此时不能全部点渲染上去
      //获取全部的数据
      let points = data.points;
      //新建一个用于存放所有点坐标的数据
      let features = [];
      let positions = [];
      //将所有点坐标存放在数组中
      for (let i=0;i<points.length;i++) {
        let position = [points[i].lng,points[i].lat];
        let featurePoint = new Feature({
          //经纬度转换为3857球形投影方式
          geometry: new Point(fromLonLat(position))
        });
        // 设置样式
        featurePoint.setStyle(
            new Style({
              //Circle 属于style中的一个样式，关于矢量要素的一个样式 里面有一些属性和配置项 fill填充
             image: new Circle({
               fill: new Fill({
                 color: this.judgeColorByWindLevel(points[i].strong)
               }),
               radius: 4,
             }),
            })
        );
        //保存数组，起始坐标与结束坐标
        if (i != points.length-1) {
          let nextPosition = [points[i+1].lng,points[i+1].lat];
          positions.push([fromLonLat(position),fromLonLat(nextPosition)]);
        }
        features.push(featurePoint);
      }

      //划线
      let featureLine = new Feature({
        geometry: new MultiLineString(positions)
      })
      features.push(featureLine)
      //新建一个矢量图层 图层中加入矢量数据源，然后图层叠加到地图上
      let layer = new VectorLayer();
      // 矢量数据源
      let source = new VectorSource();
      source.addFeatures(features);
      layer.setSource(source);
      this.map.addLayer(layer);
      console.log(data);
    },

    //画除台风路径，定时器版本
    drawTyphoonPathInterval: async function () {
      //检查是否拿到数据
      const {data} = await getTyphoonData();
      //新建一个layers然后装载数据源，数据源属性渲染，然后添加图层依据不同颜色渲染，此时不能全部点渲染上去
      //获取全部的数据
      let points = data.points;
      let index = 0;
      // 新建一个矢量层
      let layer = new VectorLayer();
      // 新建一个矢量数据源
      let source = new VectorSource();
      layer.setSource(source);
      let intervalLogo = setInterval(()=>{
          //超出长度，直接return不执行了
          if (index == points.length) {
            clearInterval(intervalLogo);
            return;
          }
          // 点 的 数据源设置
          let position = [points[index].lng,points[index].lat];
          if (index == 0) {
            this.map.getView().setCenter(fromLonLat(position));
          }
          // 点的样式设置
          let featurePoint = new Feature({
            geometry: new Point(fromLonLat(position))
          });
          // 点的颜色设置
          featurePoint.setStyle(
              new Style({
                //Circle 属于style中的一个样式，关于矢量要素的一个样式 里面有一些属性和配置项 fill填充
                image: new Circle({
                  fill: new Fill({
                    color: this.judgeColorByWindLevel(points[index].strong)
                  }),
                  radius: 4,
                }),
              })
          );
        featurePoint.set("typhoonPoint", true);
        // 数据保存到feature当中
        featurePoint.set("points", points[index]);
        if (points[index].radius7.length != 0 || points[index].radius7 != null) {
          let fetureScolar = this.drawSolar(points[index])
          if (this.lastShowSolar != null) {
            source.removeFeature(this.lastShowSolar)
          }
          this.lastShowSolar = fetureScolar
          source.addFeature(fetureScolar)
        }
        source.addFeature(featurePoint);

        // 划线
        if (index > 0) {
          let lastPosition = [points[index-1].lng,points[index-1].lat];
          let featureLine = new Feature({
            geometry: new LineString([fromLonLat(position),fromLonLat(lastPosition)])
          })
          source.addFeature(featureLine);
        }
        index++;
      },100);
      this.map.addLayer(layer);
    },

    // 注册一个hover事件
    // 注册一个 hover 事件
    designHoverOnMap: function () {
      let _this = this;
      this.map.on("pointermove", function (ev) {
        let pixel = ev.pixel;
        let feature = _this.map.forEachFeatureAtPixel(
            pixel,
            function (feature) {
              return feature;
            }
        );
        if (feature) {
          let execName = featureObj.typeJudge(feature) + "Hover";
          featureObj[execName].apply(_this, [feature]);
        } else {
          _this.clearPointZoomStyle();
          _this.map.getTargetElement().style.cursor = "";
          _this.tfOverlay.setPosition(undefined);
        }
      });
    },

    designClickOnMap: function () {
      let _this = this;
      this.map.on("click", function (ev) {
        let pixel = ev.pixel;
        let feature = _this.map.forEachFeatureAtPixel(
            pixel,
            function (feature) {
              return feature;
            }
        );
        if (feature) {
          let execName = featureObj.typeJudge(feature) + "Click";
          featureObj[execName].apply(_this, [feature]);
        } else {
          console.log("no feature");
        }
      });
    },
    clearPointZoomStyle: function (){
      let _this = this;
      if(_this.lastZoomPoint != null) {
        _this.lastZoomPoint.getStyle().getImage().setRadius(4);
        _this.lastZoomPoint.changed();
      }
    },
    //绘制台风风圈
    /**
     * 应该是明确的只让他返回 一个 feature
     */
    drawSolar:function (points) {
      let radiusArr = points.radius7.split("|").map((item)=>{
        return parseFloat(item);
      });
      // 网上所有的算法
      let Configs = {
        CIRCLE_CENTER_X: parseFloat(points.lng),
        CIRCLE_CENTER_Y: parseFloat(points.lat),
        CIRCLE_R: {
          SE: radiusArr[0] / 100,
          NE: radiusArr[1] / 100,
          NW: radiusArr[2] / 100,
          SW: radiusArr[3] / 100,
        },
      };
      let positions = [];
      let _interval = 6;
      for (let i = 0; i < 360 / _interval; i++) {
        let _r = 0;
        let _ang = i * _interval;
        if (_ang > 0 && _ang <= 90) {
          _r = Configs.CIRCLE_R.NE;
        } else if (_ang > 90 && _ang <= 180) {
          _r = Configs.CIRCLE_R.NW;
        } else if (_ang > 180 && _ang <= 270) {
          _r = Configs.CIRCLE_R.SW;
        } else {
          _r = Configs.CIRCLE_R.SE;
        }

        let x = Configs.CIRCLE_CENTER_X + _r * Math.cos((_ang * 3.14) / 180);
        let y = Configs.CIRCLE_CENTER_Y + _r * Math.sin((_ang * 3.14) / 180);
        positions.push(fromLonLat([x, y]));
      }
      // 新建数据原
      let feature = new Feature({
        geometry: new Polygon([positions]),
      });
      feature.set("typhoonSolar", true);
      return feature;
    },

    //依据台风等级判断颜色
    /**
     * @param {String} windLevel 台风等级描述
     * @param {String} map[windLevel] 台风等级颜色
     * */
    judgeColorByWindLevel: function (windLevel) {
      let map = {
        "热带风暴": 'red',
        "热带低压": 'blue',
        "强热带风暴": 'green',
        "台风": 'orange',
        "强台风": 'yellow',
        "超强台风": 'salmon'
      }
      return map[windLevel];
    },
    // 根据 约定的 类型的索引 判别 底图 与 注记图 需要渲染的layer类型
    JudgeBaseAndNoteByType(index) {
      let map = [
        ["vec", "cva"],
        ["ter", "cta"],
        ["img", "cia"],
      ];
      return map[index];
    },
    /**
     * @param {index} 想要初始化的地图类型的相关索引 支持：矢量图、影像图、地形图，分别对应 0 1 2
     * @param {key} 天地图 中申请的秘钥key
     * @param {*} centerPosition 中心点的经纬度坐标
     * @notice 参数不能为空
     */
    tiandituInit(index, key) {
      // 如果传进来的 map2d的参数为null，说明需要新建一个map地图
      if (this.map == null) {
        let layerArr = this.JudgeBaseAndNoteByType(index);
        // 地图注记 与 底图的相关配置
        console.log(layerArr);
        var projection = getProjection("EPSG:3857");
        var projectionExtent = projection.getExtent();
        var size = getWidth(projectionExtent) / 256;
        var resolutions = new Array(14);
        var matrixIds = new Array(14);
        for (var z = 0; z < 14; ++z) {
          // generate resolutions and matrixIds arrays for this WMTS
          resolutions[z] = size / Math.pow(2, z);
          matrixIds[z] = z;
        }
        let layer_Base = new TileLayer({
          opacity: 1,
          source: new WMTS({
            url:
                "http://t{0-7}.tianditu.gov.cn/" +
                layerArr[0] +
                "_w/wmts?tk=" +
                key,
            layer: layerArr[0],
            matrixSet: "w",
            format: "tiles",
            style: "default",
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
          visible: true,
        });
        let layer_Note = new TileLayer({
          opacity: 1,
          source: new WMTS({
            url:
                "http://t{0-7}.tianditu.gov.cn/" +
                layerArr[1] +
                "_w/wmts?tk=" +
                key,
            layer: layerArr[1],
            matrixSet: "w",
            format: "tiles",
            style: "default",
            tileGrid: new WMTSTileGrid({
              origin: getTopLeft(projectionExtent),
              resolutions: resolutions,
              matrixIds: matrixIds,
            }),
            wrapX: true,
          }),
          visible: true,
        });
        var map = new Map({
          layers: [layer_Base, layer_Note],
          target: "map",
          view: new View({
            center: fromLonLat([100, 20]),
            zoom: 5,
            minZoom: 4,
          }),
        });
        console.log(map);
        this.map = map;
      }
    },
    // 设置弹窗 位置
    setTFINFOPostion: function (points) {
      let position = fromLonLat([points.lng, points.lat]);
      this.tfOverlay.setPosition(position);
    },
    // 添加叠加层
    addOverlay: function () {
      const overlay = new Overlay({
        element: this.$refs.typhoonInfo.$el,
        autoPan: true,
        autoPanAnimation: {
          duration: 250,
        },
      });
      overlay.setPosition(undefined);
      this.tfOverlay = overlay;
      this.map.addOverlay(overlay);
    }
  },created() {

  },
  mounted() {
    //保存map实例，便于后续添加图层
    this.tiandituInit(0, "11748a73773880cc126562dfe4cf9047");
    this.drawTyphoonPathInterval();
    this.designHoverOnMap();
    this.addOverlay();
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.map {
  width: 100%;
  height: 100vh;
}

#map:focus {
  outline: #4A74A8 solid 0.15em;
}
</style>
